#include <retro.h>
#include "retro.creator.h"

using namespace Retro::Creator::GUI;
using namespace SPLib::Geom;

ListBase::ListBase()
{
  scroll.pos.x = scroll.pos.y = 0;
}

VOID    ListBase::onControlPaint(Controls::ControlPaintEvent& iEvent)
{
  Gdip::Rect itemBounds(
    -scroll.pos.x,
    -scroll.pos.y,
    iEvent.bounds.Width,
    itemHeight);

  INT i = 0;

  while (itemBounds.Y + itemBounds.Height < iEvent.update.top)
  {
    itemBounds.Y += itemBounds.Height;
    ++i;
  }

  iEvent.graphics.Clear(0xFFFFFFFF);

  while (itemBounds.Y < iEvent.update.bottom && i < itemCount)
  {
    paintItem(iEvent.graphics, itemBounds, i++);
    itemBounds.Y += itemBounds.Height;
  }

  paintForeground(iEvent.graphics, iEvent.bounds);
}

VOID    ListBase::onMouseWheel(Event::MouseWheelEvent& iEvent)
{
  if (GetKeyState(VK_SHIFT) >> 1) {
    setScrollX(scroll.pos.x - (INT)(
      iEvent.wheelDelta / WHEEL_DELTA * itemHeight), scroll);
  } else {
    setScrollY(scroll.pos.y - (INT)(
      iEvent.wheelDelta / WHEEL_DELTA * itemHeight), scroll);
  }
}

VOID    ListBase::onVScroll(Event::ScrollEvent& iEvent)
{
  setScrollY(calcScrollPos(iEvent.request, SB_VERT, scroll.pos.y), scroll);
}

VOID    ListBase::onSize(Event::SizeEvent& iEvent)
{
  updateScroll(Geom::Size::get(10, itemCount * itemHeight), scroll);

  Control::onSize(iEvent);
}

INT     ListBase::calcScrollPos(INT sbRequest, INT nBar, INT current)
{
  SCROLLINFO si;
  si.cbSize = sizeof(si);
  si.fMask = SIF_TRACKPOS;

  Geom::Size size = Geom::Size::fromWindow(*this);

  GetScrollInfo(*this, nBar, &si);

  switch (sbRequest)
  {
  case SB_PAGEUP:
    return current - size.cy * 5;
  case SB_PAGEDOWN:
    return current + size.cy * 5;
  case SB_LINEUP:
    return current - itemHeight;
  case SB_LINEDOWN:
    return current + itemHeight;
  case SB_THUMBPOSITION:
  case SB_THUMBTRACK:
    return si.nTrackPos;
  default:
    return current;
  }
}

VOID    ListBase::setItemCount(INT value)
{
  itemCount = value;
  updateScroll(Size::get(10, itemCount * itemHeight), scroll);
}

VOID    ListBase::invalidateItem(INT iIndex)
{
  if (iIndex < 0 || iIndex >= itemCount)
    return;

  Gdip::Rect itemBounds(
    -scroll.pos.x,
    -scroll.pos.y + itemHeight * iIndex,
    getClient().right,
    itemHeight);

  invalidate(itemBounds);
}
